﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ACompany.OrderProcessing.Infrastructure;
using ACompany.OrderProcessing.Infrastructure.Query;
using ACompany.OrderProcessing.Model;
using ACompany.OrderProcessing.NHibernateRepository;

namespace ACompany.OrderProcessing.Services
{
    public class OrderService : IOrderService
    {
        private readonly IOrderRepository _orderRepository;
        private readonly IProductRepository _productRepository;
        private readonly IUnitOfWork _unitOfWork;

        #region Ctors



        public OrderService()
            : this(new OrderRepository(), new ProductRepository(), new MHibernateUnitOfWork())
        {

        }

        public OrderService(IOrderRepository orderRepository, IProductRepository productRepository, IUnitOfWork unitOfWork)
        {
            _productRepository = productRepository;
            this._productRepository.Inject(unitOfWork);
            _orderRepository = orderRepository;
            this._orderRepository.Inject(unitOfWork);
            _unitOfWork = unitOfWork;
        }
        #endregion


        public List<Order> GetAllOrdersBy(OrderStatus status)
        {
            Query orderStatusQuery = new Query();
            Criteria orderStatusCriteria = new Criteria("Status", status, CriteriaOperator.Equals);
            orderStatusQuery.Criteria.Add(orderStatusCriteria);

            return _orderRepository.FindBy(orderStatusQuery).ToList();
        }

        public void Save(Order order)
        {
            if (order.GetBrokenRules().Count == 0)
            {
                //             order.Items[0].Product.Stock
                _orderRepository.Save(order);
                _unitOfWork.Commit();
            }
            else
            {
                throw new InvalidOperationException(string.Format("the order cannot be saved in this state : {0}", BuildErrorListFrom(order)));
            }
        }

        private string BuildErrorListFrom(Order order)
        {
            var sb = new StringBuilder();
            foreach (var brokenRule in order.GetBrokenRules())
                sb.AppendLine(brokenRule.Rule);
            return sb.ToString();
        }

        public IList<Order> FindAllOrdersContainingProductby(Guid productId)
        {
            return _orderRepository.FindAllOrdersContainingProductby(productId);

        }

        public Order FindBy(Guid id)
        {
            return _orderRepository.FindBy(id);
        }

        public void Place(Order order)
        {
            _orderRepository.Save(order);
            _unitOfWork.Commit();
        }

        public void Process(Order order)
        {
            if (order.CanProcess())
            {
                order.Process();
                foreach (Item item in order.Items)
                {
                    item.Product.Stock -= item.Qty;
                    _productRepository.Save(item.Product);
                }
                _orderRepository.Save(order);
                _unitOfWork.Commit();
            }
            else
            {
                throw new InvalidOperationException("this order cannot be processed");
            }
        }
    }
}
